using PKGames;
using PKGames.Localization;
using PKGames.MiniGames.VoxelGame.Scripts.World;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using UnityEngine;
using VoxelEngine.TerrainGenerator;
using VoxelEngine.Utils;
using VoxelGame;

namespace VoxelEngine
{
	public class BaseWorldController : BaseGameController, ISupportedLanguagesResolver
	{
		[Header("Debug")]
		[SerializeField]
		private bool _showHeightMapGizmos;

		[SerializeField]
		private bool _showChunksBoundingBox;

		[Header("World")]
		[SerializeField]
		protected VoxelEngine.TerrainGenerator.TerrainGenerator _terrainGenerator;

		[SerializeField]
		private ChunkObject _chunkPrefab;

		[SerializeField]
		private Transform _worldTransform;

		[SerializeField]
		private bool _voxelBorder = true;

		[SerializeField]
		private UiController _uiController;

		[SerializeField]
		private bool _forceWorldGeneration;

		[Header("Lightining")]
		[SerializeField]
		private bool _smoothLight = true;

		[Header("World Management")]
		[SerializeField]
		protected Vector3i _worldSize;

		[SerializeField]
		protected bool _autoSaveWorld;

		[Header("Save")]
		[SerializeField]
		protected float _saveInterval = 60f;

		protected World _world;

		protected string _worldId;

		private bool _worldLoaded;

		private bool _quitting;

		protected Dictionary<VoxelProp.PropType, VoxelProp> _voxelProps = new Dictionary<VoxelProp.PropType, VoxelProp>
		{
			{
				VoxelProp.PropType.Tree,
				new TreeProp()
			}
		};

		public static WorldSelectionConfig VoxelPlayerData
		{
			get;
			set;
		}

		public static Action OnDisableAction
		{
			get;
			set;
		}

		protected void EnableWorldCurvature()
		{
			Shader.SetGlobalFloat("_Curvature", 0.004f);
		}

		protected void DisableWorldCurvature()
		{
			Shader.SetGlobalFloat("_Curvature", 0f);
		}

		protected void Awake()
		{
			_worldId = ((!(VoxelPlayerData != null) || !(VoxelPlayerData.VoxelWorldData != null)) ? "unavailable" : VoxelPlayerData.VoxelWorldData.WorldId);
			ResourceAsset worldAsset = (!(VoxelPlayerData != null)) ? null : VoxelPlayerData.VoxelWorldData.SerializedWorld;
			_uiController.Setup(IsTrialAvailable, VoxelPlayerData.IconTexture, RegisterTrialEnded, 
                //VoxelPlayerData.Product,
                null,
                _worldId, VoxelPlayerData.VoxelWorldData.BlockSelection);
			_world = new World(_worldId, worldAsset, _worldSize);
			ChunkRenderer.SmoothLight = _smoothLight;
			ChunkRenderer.VoxelBorder = _voxelBorder;
			ChunkRenderer.WorldHeight = new float[_world.WorldVisibleSizeX, _world.WorldVisibleSizeZ];
		}

		protected bool IsTrialAvailable()
		{
			return VoxelPlayerData.CurrentWorldState == WorldSelectionConfig.WorldState.Trial;
		}

		private void RegisterTrialEnded()
		{
			VoxelPlayerData.TrialEnabled = false;
		}

		protected override void OnDestroy()
		{
			base.OnDestroy();
			if (_worldLoaded)
			{
				try
				{
					SaveWorld();
					UnityEngine.Debug.Log("[Voxel] World Saved!");
				}
				catch (IOException)
				{
				}
			}
			else
			{
				UnityEngine.Debug.Log("[Voxel] World save failure!");
			}
			VoxelPlayerData = null;
			ChunkObject.Clear();
		}

		protected override void OnBack()
		{
			if (!_quitting)
			{
				_quitting = true;
				SaveAndQuit();
			}
		}

		private void SaveWorld()
		{
			if (_worldLoaded)
			{
				_world.SaveSync();
			}
			else
			{
				UnityEngine.Debug.Log("World save failure - world not loaded");
			}
		}

		private void SaveAndQuit()
		{
			SaveWorld();
			UnityEngine.Debug.Log("World Saved!");
			base.OnBack();
		}

		protected IEnumerator LoadWorld()
        {
            UnityEngine.Debug.Log("LoadWorld");
            bool worldLoaded = false;
			bool loadFinished = false;
			Stopwatch stopWatch = new Stopwatch();
            UnityEngine.Debug.Log("LoadWorld2");
            stopWatch.Start();
            UnityEngine.Debug.Log("LoadWorld3");
            if (_forceWorldGeneration)
            {
                UnityEngine.Debug.Log("LoadWorld4-a");
                stopWatch.Start();
                UnityEngine.Debug.Log("LoadWorld4-a2");
                yield return StartCoroutine(_terrainGenerator.CreateWorldFromSeed(_world));
                UnityEngine.Debug.Log("LoadWorld4-a3");
                stopWatch.Stop();
                UnityEngine.Debug.Log("LoadWorld4-a4");
                UnityEngine.Debug.Log("[Voxel] World Created From Seed in: " + stopWatch.ElapsedMilliseconds + " ms");
				stopWatch.Reset();
				stopWatch.Start();
				SaveWorld();
				stopWatch.Stop();
				UnityEngine.Debug.Log("[Voxel] World Saved in: " + stopWatch.ElapsedMilliseconds + " ms");
				yield break;
            }
            UnityEngine.Debug.Log("LoadWorld5");
            //         _world.LoadAsync(delegate(bool success)
            //         {
            //             UnityEngine.Debug.Log("LoadWorld5-a");
            //             loadFinished = true;
            worldLoaded = false;
            //});
            UnityEngine.Debug.Log("LoadWorld6");
            //while (!loadFinished)
            //{
            //    UnityEngine.Debug.Log("LoadWorld7");
            //    yield return null;
            //}
            UnityEngine.Debug.Log("LoadWorld8");
            stopWatch.Stop();
            UnityEngine.Debug.Log("LoadWorld9");
            UnityEngine.Debug.Log("[Voxel] World Loaded in: " + stopWatch.ElapsedMilliseconds + " ms");
			if (!worldLoaded)
			{
				stopWatch.Reset();
				stopWatch.Start();
				yield return StartCoroutine(_world.LoadFromAssetBundle(this, delegate(bool success)
				{
					worldLoaded = success;
				}));
				UnityEngine.Debug.Log("[Voxel] Embedded World Loaded in: " + stopWatch.ElapsedMilliseconds + " ms");
			}
		}

		protected IEnumerator CreateWorldMesh(float maxProgress = 1f)
		{
			int total = World.VisibleX * World.VisibleY * World.VisibleZ;
			int count = 0;
			int step = Mathf.CeilToInt((float)total * 0.15f);
			UnityEngine.Debug.Log("[Voxel] Creating World Mesh");
			OnCreateWorldMeshProgress(0f);
			Stopwatch stopwatch = new Stopwatch();
			stopwatch.Start();
			for (int x = 0; x < World.VisibleX; x++)
			{
				for (int y = 0; y < World.VisibleY; y++)
				{
					for (int z = 0; z < World.VisibleZ; z++)
					{
						Stopwatch stopwatchChunk = new Stopwatch();
						stopwatchChunk.Start();
						CreateChunkMesh(x, y, z);
						count++;
						if (count % step == 0)
						{
							yield return null;
							OnCreateWorldMeshProgress(Mathf.Lerp(0f, maxProgress, (float)count / (float)total));
						}
					}
				}
			}
			yield return StartCoroutine(_terrainGenerator.DrawProps(_world));
			OnCreateWorldMeshProgress(maxProgress);
			UnityEngine.Debug.Log("[Voxel] World created in: " + stopwatch.ElapsedMilliseconds + " ms");
			_worldLoaded = true;
			if (_autoSaveWorld)
			{
				InvokeRepeating("SaveWorld", _saveInterval, _saveInterval);
			}
		}

		protected virtual void OnCreateWorldMeshProgress(float progress)
		{
		}

		protected virtual void OnCreateWorldMeshFinished()
		{
		}

		protected virtual void StartGame()
		{
		}

		protected virtual IEnumerator CreateWorldFromSeed()
		{
			yield return null;
		}

		private void CreateChunkMesh(int x, int y, int z)
		{
			ChunkObject chunkObject = UnityEngine.Object.Instantiate(_chunkPrefab);
			chunkObject.name = "Chunk[" + x + "," + y + "," + z + "]";
			chunkObject.transform.parent = _worldTransform;
			Vector3 position = default(Vector3);
			position.x = x << 3;
			position.y = y << 3;
			position.z = z << 3;
			chunkObject.transform.position = position;
			_world.CreateChunkMesh(x, y, z, chunkObject);
		}

		public virtual string FilterSupportedLanguage(string languageCode)
		{
			return Language.English.ToString();
		}

		protected new virtual void OnApplicationPause(bool pause)
		{
			base.OnApplicationPause(pause);
			if (pause)
			{
				SaveWorld();
			}
		}
	}
}
